home *** CD-ROM | disk | FTP | other *** search
/ PC/CD Gamer UK 120 / CD Gamer Issue 120 (March 2003) (Disc 2).ISO / mods / Q2_Codered / codeRED1_0.exe / Data1.cab / snd_mix.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-08-13  |  10.7 KB  |  500 lines

  1. /*
  2. Copyright (C) 1997-2001 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. // snd_mix.c -- portable code to mix sounds for snd_dma.c
  21.  
  22. #include "client.h"
  23. #include "snd_loc.h"
  24.  
  25. #define    PAINTBUFFER_SIZE    2048
  26. portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];
  27. int        snd_scaletable[32][256];
  28. int     *snd_p, snd_linear_count, snd_vol;
  29. short    *snd_out;
  30.  
  31. void S_WriteLinearBlastStereo16 (void);
  32.  
  33. #if !(defined __linux__ && defined __i386__)
  34. #if    !id386
  35.  
  36. void S_WriteLinearBlastStereo16 (void)
  37. {
  38.     int        i;
  39.     int        val;
  40.  
  41.     for (i=0 ; i<snd_linear_count ; i+=2)
  42.     {
  43.         val = snd_p[i]>>8;
  44.         if (val > 0x7fff)
  45.             snd_out[i] = 0x7fff;
  46.         else if (val < (short)0x8000)
  47.             snd_out[i] = (short)0x8000;
  48.         else
  49.             snd_out[i] = val;
  50.  
  51.         val = snd_p[i+1]>>8;
  52.         if (val > 0x7fff)
  53.             snd_out[i+1] = 0x7fff;
  54.         else if (val < (short)0x8000)
  55.             snd_out[i+1] = (short)0x8000;
  56.         else
  57.             snd_out[i+1] = val;
  58.     }
  59. }
  60. #else
  61. __declspec( naked ) void S_WriteLinearBlastStereo16 (void)
  62. {
  63.     __asm {
  64.  
  65.  push edi
  66.  push ebx
  67.  mov ecx,ds:dword ptr[snd_linear_count]
  68.  mov ebx,ds:dword ptr[snd_p]
  69.  mov edi,ds:dword ptr[snd_out]
  70. LWLBLoopTop:
  71.  mov eax,ds:dword ptr[-8+ebx+ecx*4]
  72.  sar eax,8
  73.  cmp eax,07FFFh
  74.  jg LClampHigh
  75.  cmp eax,0FFFF8000h
  76.  jnl LClampDone
  77.  mov eax,0FFFF8000h
  78.  jmp LClampDone
  79. LClampHigh:
  80.  mov eax,07FFFh
  81. LClampDone:
  82.  mov edx,ds:dword ptr[-4+ebx+ecx*4]
  83.  sar edx,8
  84.  cmp edx,07FFFh
  85.  jg LClampHigh2
  86.  cmp edx,0FFFF8000h
  87.  jnl LClampDone2
  88.  mov edx,0FFFF8000h
  89.  jmp LClampDone2
  90. LClampHigh2:
  91.  mov edx,07FFFh
  92. LClampDone2:
  93.  shl edx,16
  94.  and eax,0FFFFh
  95.  or edx,eax
  96.  mov ds:dword ptr[-4+edi+ecx*2],edx
  97.  sub ecx,2
  98.  jnz LWLBLoopTop
  99.  pop ebx
  100.  pop edi
  101.  ret
  102.     }
  103. }
  104.  
  105. #endif
  106. #endif
  107.  
  108. void S_TransferStereo16 (unsigned long *pbuf, int endtime)
  109. {
  110.     int        lpos;
  111.     int        lpaintedtime;
  112.     
  113.     snd_p = (int *) paintbuffer;
  114.     lpaintedtime = paintedtime;
  115.  
  116.     while (lpaintedtime < endtime)
  117.     {
  118.     // handle recirculating buffer issues
  119.         lpos = lpaintedtime & ((dma.samples>>1)-1);
  120.  
  121.         snd_out = (short *) pbuf + (lpos<<1);
  122.  
  123.         snd_linear_count = (dma.samples>>1) - lpos;
  124.         if (lpaintedtime + snd_linear_count > endtime)
  125.             snd_linear_count = endtime - lpaintedtime;
  126.  
  127.         snd_linear_count <<= 1;
  128.  
  129.     // write a linear blast of samples
  130.         S_WriteLinearBlastStereo16 ();
  131.  
  132.         snd_p += snd_linear_count;
  133.         lpaintedtime += (snd_linear_count>>1);
  134.     }
  135. }
  136.  
  137. /*
  138. ===================
  139. S_TransferPaintBuffer
  140.  
  141. ===================
  142. */
  143. void S_TransferPaintBuffer(int endtime)
  144. {
  145.     int     out_idx;
  146.     int     count;
  147.     int     out_mask;
  148.     int     *p;
  149.     int     step;
  150.     int        val;
  151.     unsigned long *pbuf;
  152.  
  153.     pbuf = (unsigned long *)dma.buffer;
  154.  
  155.     if (s_testsound->value)
  156.     {
  157.         int        i;
  158.         int        count;
  159.  
  160.         // write a fixed sine wave
  161.         count = (endtime - paintedtime);
  162.         for (i=0 ; i<count ; i++)
  163.             paintbuffer[i].left = paintbuffer[i].right = sin((paintedtime+i)*0.1)*20000*256;
  164.     }
  165.  
  166.  
  167.     if (dma.samplebits == 16 && dma.channels == 2)
  168.     {    // optimized case
  169.         S_TransferStereo16 (pbuf, endtime);
  170.     }
  171.     else
  172.     {    // general case
  173.         p = (int *) paintbuffer;
  174.         count = (endtime - paintedtime) * dma.channels;
  175.         out_mask = dma.samples - 1; 
  176.         out_idx = paintedtime * dma.channels & out_mask;
  177.         step = 3 - dma.channels;
  178.  
  179.         if (dma.samplebits == 16)
  180.         {
  181.             short *out = (short *) pbuf;
  182.             while (count--)
  183.             {
  184.                 val = *p >> 8;
  185.                 p+= step;
  186.                 if (val > 0x7fff)
  187.                     val = 0x7fff;
  188.                 else if (val < (short)0x8000)
  189.                     val = (short)0x8000;
  190.                 out[out_idx] = val;
  191.                 out_idx = (out_idx + 1) & out_mask;
  192.             }
  193.         }
  194.         else if (dma.samplebits == 8)
  195.         {
  196.             unsigned char *out = (unsigned char *) pbuf;
  197.             while (count--)
  198.             {
  199.                 val = *p >> 8;
  200.                 p+= step;
  201.                 if (val > 0x7fff)
  202.                     val = 0x7fff;
  203.                 else if (val < (short)0x8000)
  204.                     val = (short)0x8000;
  205.                 out[out_idx] = (val>>8) + 128;
  206.                 out_idx = (out_idx + 1) & out_mask;
  207.             }
  208.         }
  209.     }
  210. }
  211.  
  212.  
  213. /*
  214. ===============================================================================
  215.  
  216. CHANNEL MIXING
  217.  
  218. ===============================================================================
  219. */
  220.  
  221. void S_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int endtime, int offset);
  222. void S_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int endtime, int offset);
  223.  
  224. void S_PaintChannels(int endtime)
  225. {
  226.     int     i;
  227.     int     end;
  228.     channel_t *ch;
  229.     sfxcache_t    *sc;
  230.     int        ltime, count;
  231.     playsound_t    *ps;
  232.  
  233.     snd_vol = s_volume->value*256;
  234.  
  235. //Com_Printf ("%i to %i\n", paintedtime, endtime);
  236.     while (paintedtime < endtime)
  237.     {
  238.     // if paintbuffer is smaller than DMA buffer
  239.         end = endtime;
  240.         if (endtime - paintedtime > PAINTBUFFER_SIZE)
  241.             end = paintedtime + PAINTBUFFER_SIZE;
  242.  
  243.         // start any playsounds
  244.         while (1)
  245.         {
  246.             ps = s_pendingplays.next;
  247.             if (ps == &s_pendingplays)
  248.                 break;    // no more pending sounds
  249.             if (ps->begin <= paintedtime)
  250.             {
  251.                 S_IssuePlaysound (ps);
  252.                 continue;
  253.             }
  254.  
  255.             if (ps->begin < end)
  256.                 end = ps->begin;        // stop here
  257.             break;
  258.         }
  259.  
  260.     // clear the paint buffer
  261.         if (s_rawend < paintedtime)
  262.         {
  263. //            Com_Printf ("clear\n");
  264.             memset(paintbuffer, 0, (end - paintedtime) * sizeof(portable_samplepair_t));
  265.         }
  266.         else
  267.         {    // copy from the streaming sound source
  268.             int        s;
  269.             int        stop;
  270.  
  271.             stop = (end < s_rawend) ? end : s_rawend;
  272.  
  273.             for (i=paintedtime ; i<stop ; i++)
  274.             {
  275.                 s = i&(MAX_RAW_SAMPLES-1);
  276.                 paintbuffer[i-paintedtime] = s_rawsamples[s];
  277.             }
  278. //        if (i != end)
  279. //            Com_Printf ("partial stream\n");
  280. //        else
  281. //            Com_Printf ("full stream\n");
  282.             for ( ; i<end ; i++)
  283.             {
  284.                 paintbuffer[i-paintedtime].left =
  285.                 paintbuffer[i-paintedtime].right = 0;
  286.             }
  287.         }
  288.  
  289.  
  290.     // paint in the channels.
  291.         ch = channels;
  292.         for (i=0; i<MAX_CHANNELS ; i++, ch++)
  293.         {
  294.             ltime = paintedtime;
  295.         
  296.             while (ltime < end)
  297.             {
  298.                 if (!ch->sfx || (!ch->leftvol && !ch->rightvol) )
  299.                     break;
  300.  
  301.                 // max painting is to the end of the buffer
  302.                 count = end - ltime;
  303.  
  304.                 // might be stopped by running out of data
  305.                 if (ch->end - ltime < count)
  306.                     count = ch->end - ltime;
  307.         
  308.                 sc = S_LoadSound (ch->sfx);
  309.                 if (!sc)
  310.                     break;
  311.  
  312.                 if (count > 0 && ch->sfx)
  313.                 {    
  314.                     if (sc->width == 1)// FIXME; 8 bit asm is wrong now
  315.                         S_PaintChannelFrom8(ch, sc, count,  ltime - paintedtime);
  316.                     else
  317.                         S_PaintChannelFrom16(ch, sc, count, ltime - paintedtime);
  318.     
  319.                     ltime += count;
  320.                 }
  321.  
  322.             // if at end of loop, restart
  323.                 if (ltime >= ch->end)
  324.                 {
  325.                     if (ch->autosound)
  326.                     {    // autolooping sounds always go back to start
  327.                         ch->pos = 0;
  328.                         ch->end = ltime + sc->length;
  329.                     }
  330.                     else if (sc->loopstart >= 0)
  331.                     {
  332.                         ch->pos = sc->loopstart;
  333.                         ch->end = ltime + sc->length - ch->pos;
  334.                     }
  335.                     else                
  336.                     {    // channel just stopped
  337.                         ch->sfx = NULL;
  338.                     }
  339.                 }
  340.             }
  341.                                                               
  342.         }
  343.  
  344.     // transfer out according to DMA format
  345.         S_TransferPaintBuffer(end);
  346.         paintedtime = end;
  347.     }
  348. }
  349.  
  350. void S_InitScaletable (void)
  351. {
  352.     int        i, j;
  353.     int        scale;
  354.  
  355.     s_volume->modified = false;
  356.     for (i=0 ; i<32 ; i++)
  357.     {
  358.         scale = i * 8 * 256 * s_volume->value;
  359.         for (j=0 ; j<256 ; j++)
  360.             snd_scaletable[i][j] = ((signed char)j) * scale;
  361.     }
  362. }
  363.  
  364.  
  365. #if !(defined __linux__ && defined __i386__)
  366. #if    !id386
  367.  
  368. void S_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count, int offset)
  369. {
  370.     int     data;
  371.     int        *lscale, *rscale;
  372.     unsigned char *sfx;
  373.     int        i;
  374.     portable_samplepair_t    *samp;
  375.  
  376.     if (ch->leftvol > 255)
  377.         ch->leftvol = 255;
  378.     if (ch->rightvol > 255)
  379.         ch->rightvol = 255;
  380.         
  381.     //ZOID-- >>11 has been changed to >>3, >>11 didn't make much sense
  382.     //as it would always be zero.
  383.     lscale = snd_scaletable[ ch->leftvol >> 3];
  384.     rscale = snd_scaletable[ ch->rightvol >> 3];
  385.     sfx = (signed char *)sc->data + ch->pos;
  386.  
  387.     samp = &paintbuffer[offset];
  388.  
  389.     for (i=0 ; i<count ; i++, samp++)
  390.     {
  391.         data = sfx[i];
  392.         samp->left += lscale[data];
  393.         samp->right += rscale[data];
  394.     }
  395.     
  396.     ch->pos += count;
  397. }
  398.  
  399. #else
  400.  
  401. __declspec( naked ) void S_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count, int offset)
  402. {
  403.     __asm {
  404.  push esi
  405.  push edi
  406.  push ebx
  407.  push ebp
  408.  mov ebx,ds:dword ptr[4+16+esp]
  409.  mov esi,ds:dword ptr[8+16+esp]
  410.  mov eax,ds:dword ptr[4+ebx]
  411.  mov edx,ds:dword ptr[8+ebx]
  412.  cmp eax,255
  413.  jna LLeftSet
  414.  mov eax,255
  415. LLeftSet:
  416.  cmp edx,255
  417.  jna LRightSet
  418.  mov edx,255
  419. LRightSet:
  420.  and eax,0F8h
  421.  add esi,20
  422.  and edx,0F8h
  423.  mov edi,ds:dword ptr[16+ebx]
  424.  mov ecx,ds:dword ptr[12+16+esp]
  425.  add esi,edi
  426.  shl eax,7
  427.  add edi,ecx
  428.  shl edx,7
  429.  mov ds:dword ptr[16+ebx],edi
  430.  add eax,offset snd_scaletable
  431.  add edx,offset snd_scaletable
  432.  sub ebx,ebx
  433.  mov bl,ds:byte ptr[-1+esi+ecx*1]
  434.  test ecx,1
  435.  jz LMix8Loop
  436.  mov edi,ds:dword ptr[eax+ebx*4]
  437.  mov ebp,ds:dword ptr[edx+ebx*4]
  438.  add edi,ds:dword ptr[paintbuffer+0-8+ecx*8]
  439.  add ebp,ds:dword ptr[paintbuffer+4-8+ecx*8]
  440.  mov ds:dword ptr[paintbuffer+0-8+ecx*8],edi
  441.  mov ds:dword ptr[paintbuffer+4-8+ecx*8],ebp
  442.  mov bl,ds:byte ptr[-2+esi+ecx*1]
  443.  dec ecx
  444.  jz LDone
  445. LMix8Loop:
  446.  mov edi,ds:dword ptr[eax+ebx*4]
  447.  mov ebp,ds:dword ptr[edx+ebx*4]
  448.  add edi,ds:dword ptr[paintbuffer+0-8+ecx*8]
  449.  add ebp,ds:dword ptr[paintbuffer+4-8+ecx*8]
  450.  mov bl,ds:byte ptr[-2+esi+ecx*1]
  451.  mov ds:dword ptr[paintbuffer+0-8+ecx*8],edi
  452.  mov ds:dword ptr[paintbuffer+4-8+ecx*8],ebp
  453.  mov edi,ds:dword ptr[eax+ebx*4]
  454.  mov ebp,ds:dword ptr[edx+ebx*4]
  455.  mov bl,ds:byte ptr[-3+esi+ecx*1]
  456.  add edi,ds:dword ptr[paintbuffer+0-8*2+ecx*8]
  457.  add ebp,ds:dword ptr[paintbuffer+4-8*2+ecx*8]
  458.  mov ds:dword ptr[paintbuffer+0-8*2+ecx*8],edi
  459.  mov ds:dword ptr[paintbuffer+4-8*2+ecx*8],ebp
  460.  sub ecx,2
  461.  jnz LMix8Loop
  462. LDone:
  463.  pop ebp
  464.  pop ebx
  465.  pop edi
  466.  pop esi
  467.  ret
  468.     }
  469. }
  470.  
  471. #endif
  472. #endif
  473.  
  474. void S_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count, int offset)
  475. {
  476.     int data;
  477.     int left, right;
  478.     int leftvol, rightvol;
  479.     signed short *sfx;
  480.     int    i;
  481.     portable_samplepair_t    *samp;
  482.  
  483.     leftvol = ch->leftvol*snd_vol;
  484.     rightvol = ch->rightvol*snd_vol;
  485.     sfx = (signed short *)sc->data + ch->pos;
  486.  
  487.     samp = &paintbuffer[offset];
  488.     for (i=0 ; i<count ; i++, samp++)
  489.     {
  490.         data = sfx[i];
  491.         left = (data * leftvol)>>8;
  492.         right = (data * rightvol)>>8;
  493.         samp->left += left;
  494.         samp->right += right;
  495.     }
  496.  
  497.     ch->pos += count;
  498. }
  499.  
  500.